#pragma once
#include "stdafx.h"
#include "node.h"
#include "Parameter.h"
#include "..//NilKey.h"
#include "..//VectorKey.h"
class CMKadNode :
	public CNode 
{
	friend class CGlobalOperator;
	struct key_less
	{
		bool operator()(const KEY  &cLeft,const KEY  & cRight)
		{
			return CMKadNode::Compare(cLeft,cRight)<0;
		};
	};

	struct pair_key_less
	{
		bool operator()(const pair<int,KEY>  &cLeft,const pair<int,KEY>  & cRight)
		{
			if(cLeft.first == cRight.first)
			{
				return CMKadNode::Compare(cLeft.second ,cRight.second )<0;
			}
			else
			{
				return cLeft.first<cRight.first;
			}
		};
	};
public:
	CMKadNode(const NODE_INDEX nNodeIndex);
	virtual~CMKadNode(void);
	bool InsertData( const KEY &cKey,  const CValue &cValue);
	bool FindLocalNode(const KEY &cId,const int nMaxDis,const int nMaxNo,set<NODE_INDEX>& cStorer);
	bool FindLocalData(const KEY &cKey,const int nMaxDis,const int nMaxNo,vector<pair<KEY,CValue>>& cStorer);
	virtual void OnTimer(const TIMER_TYPE dwType);
	virtual void OnJoin(void);
	virtual void OnLeave(void);
	void OnGossip(void);
	bool FindRemoteNode(const KEY &cId,const int nMaxDis,const int nMaxDepth,const int nMaxNo,set<NODE_INDEX>& cStorer );
	bool FindRemoteNode(const KEY &cId,const int nDistance,const int nMaxDeviation,const int nMaxDepth,const int nMaxNo,set<NODE_INDEX>& cStorer );
	int FindRemoteNodeForTest(const KEY &cId,const int nMaxDepth);
	bool FindRemoteData(const KEY &key,const int nMaxDis,const int nMaxDepth,const int nMaxNo,vector<pair<KEY,CValue>>& cStorer,unsigned int &nAccessNode,unsigned int &nAccessData);
	bool Publish(const KEY & key, const CValue & value);
private:
	KEY m_cId;
	map<KEY ,CValue, key_less> m_cLocalData;
	vector<set<NODE_INDEX>> m_cBudget;
	int m_nRadius;
	inline void CalculateRadius()
	{
		m_nRadius = 0;
		for(map<KEY ,CValue, key_less>::iterator it = m_cLocalData.begin();it!=m_cLocalData.end();++it)
		{
			m_nRadius = max(m_nRadius,GetDistance(m_cId,it->first));
		}
	
	};
//-------------------------for gossip----------------------------
	int m_nGossipCount;
	NODE_INDEX m_nRichestNode;
	set<pair<int,NODE_INDEX>,pair_less<int,NODE_INDEX>> m_cCandidateNode;
	
//----------------------end of for gossip------------------------
	bool  FindRemoteDataHelper(const KEY &key,const int nMaxDis,map<pair<int,KEY>,CValue,pair_key_less> &cResult);
	void Join(void);
	void Leave(void);
	bool GetSuitableNodeForReponseGossip(const KEY & cId, set<pair<int,NODE_INDEX>,pair_less<int,NODE_INDEX>> & cStorer);
	inline int GetBudgetPos(const KEY &cId)
	{
		int nDis = GetDistance(cId,this->m_cId);
		for(int i = 0;i<BUDGET_NUM;i++)
		{
			if(nDis<=ROUTER_DISTANCE_TABLE[i])
			{
				return i;
			}
		}
		return -1;
	};
	inline void AddCandidateNode(const NODE_INDEX nIndex)
	{
		CMKadNode* pNode = this->GetNode(nIndex);
		if(pNode!=NULL)
		{
			this->m_cCandidateNode.insert(make_pair(this->GetBudgetPos(pNode->m_cId),nIndex));
			pNode->m_cCandidateNode.insert(make_pair(pNode->GetBudgetPos(this->m_cId),nIndex));
		}
	}
private:
	static inline int Compare(const KEY  &cLeft,const KEY  & cRight)
	{
		return KEY::Compare(cLeft,cRight);
	}
	static inline int GetDistance(const KEY  &cLeft,const KEY  & cRight)
	{
		return KEY::GetDistance(cLeft,cRight);
	}
	static CMKadNode* GetNode(NODE_INDEX nIndex);
	
public:	
	inline const KEY& GetNodeID() const
	{
		return m_cId;
	};
	inline int GetGossipCount()const
	{
		return m_nGossipCount;
	};
	inline int GetDataCount()const
	{
		return m_cLocalData.size();
	};
	inline int GetValidBudgetItemCount()const
	{
		int nRes = 0;
		for(int i = 0;i<(int)m_cBudget.size();i++)
		{
			nRes+=m_cBudget[i].size();
		}
		return nRes;
	};
	inline void GetBudgetList(set<NODE_INDEX> &cStorer)
	{
		for(int i = 0;i<BUDGET_NUM;i++)
		{
			cStorer.insert(m_cBudget[i].begin(),m_cBudget[i].end());
		}
	};
private:
	void OnRepublish(void);
};
